<template>
  <div class="proxy-test-event">
    <h1>{{ message }}</h1>
    <p>在实际开发中，可能会需要监听某个DOM的变化，而window的resize发生变化时dom并不一定有变化，而DOM有变化时又不一定会触发resize,这时候就需要我们自己来添加DOMResize事件。</p>
    <p>大概有以下几种思路：</p>
    <ol>
        <li>利用setTimeout,给自己想监听的DOM添加定时器。</li>
        <li>利用iframe，监听contentWindow的resize事件</li>
        <li>利用MutationObserver监听DOM的变化</li>
    </ol>
    <section>
        <h3>1、利用setTimeout,给自己想监听的DOM添加定时器。</h3>
        <p>优点：兼容性好</p>
        <p>缺点：会添加一些定时器，太频繁会对浏览器有一些压力，在两次计时器之间做的变动不会触发resize.</p>
        <p>jquery的resize插件类似的思路：<a href="https://cdn.bootcss.com/jquery-resize/1.1/jquery.ba-resize.min.js">传送门</a></p>
        <div class="flex">
            <div class="left set-time-out-left">
                <div id="set-time-out-left" class="left-contain"></div>
                快速点击右侧改变宽高
            </div>
            <div class="right">
                <span class="btn" @click="changeDom1">改变大小</span>
                <span class="btn" @click="cancelDom1">结束改变</span>
                <div v-if="randomTxt" class="context">
                    监测到dom宽高改变为：{{randomTxt}}
                </div>
            </div>
        </div>
        <code>
            <pre>
                let vm = this;
                class setInter {
                    interid: any;
                    dom: any;
                    fn: any;
                    oldParams: any = {
                        width: '',
                        height: ''
                    };
                    constructor(dom: HTMLElement, fn: Function) {
                        this.dom = dom;
                        this.fn = fn;
                    }
                    start() {
                        this.interid = setInterval(() => {
                            let width = this.dom.style.width;
                            let height = this.dom.style.height
                            if (width != this.oldParams.width || height != this.oldParams.height) {
                                this.fn({
                                    width,
                                    height
                                })
                                this.oldParams.width = width;
                                this.oldParams.height = height;
                            }
                        }, 500);
                    }
                    end() {
                        clearInterval(this.interid);
                    }
                }

                let dom1 = new setInter(document.getElementById('set-time-out-left') as HTMLElement, function (res) {
                    vm.randomTxt = `width:${res.width}, height:${res.height}`;
                });
                dom1.start();
            </pre>
        </code>
    </section>
    <section>
        <h3>2、利用iframe，监听contentWindow的resize事件</h3>
        <p>优点：兼容性好，不需要自己添加新的事件</p>
        <p>缺点：渲染出来到处都是iframe,页面看起来有些杂乱。</p>
        <div class="flex">
            <div class="left">
                <div class="left-contain" id="iframe-left">

                </div>
                点击右侧改变大小
            </div>
            <div class="right">
                <span @click="change2dom" class="btn">点击改变大小</span>
                <div v-if="randomTxt2" class="context">
                    监测到dom宽高改变为：{{randomTxt2}}
                </div>
            </div>
        </div>
        <code>
            <pre>
                function resize2 (dom:HTMLElement, cb: Function) {
                    this.el = dom;
                    this.cb = cb;
                    this.init();
                }
                resize2.prototype.init = function () {
                    let iframe = document.createElement('iframe') as HTMLIFrameElement;
                    this.el.style.position = 'relative';

                    let style = {
                        opacity: 0,
                        'z-index': '-9999',
                        position: 'absolute',
                        left: 0,
                        top: 0,
                        width: '100%',
                        height: '100%',
                    };
                    let styleText = '';
                    for (const key in style) {
                        styleText += (key + ':' + style[key] + ';');
                    }
                    iframe.style.cssText = styleText;

                    this.el.appendChild(iframe);
                    let self = this;
                    (iframe.contentWindow as Window).addEventListener('resize', function() {
                        self.cb({
                            width: self.el.style.width,
                            height: self.el.style.height
                        });
                    }, false);
                }

                new resize2(document.getElementById('iframe-left') as HTMLElement, function (res) {
                    vm.randomTxt2 = `width:${res.width}, height:${res.height}`;
                });
            </pre>
        </code>
    </section>
    <section>
        <h3>3、利用MutationObserver监听DOM的变化</h3>
        <p>优点：原生方法相对定时器开销低，相对定时器比较稳定</p>
        <p>缺点：渲兼容性不是很可观。</p>
        <div class="flex">
            <div class="left">
                <div class="left-contain" id="MutationObserver">
                </div>
                点击右侧改变大小
            </div>
            <div class="right">
                <span @click="change3dom" class="btn">点击改变大小</span>
                <div v-if="randomTxt3" class="context">
                    监测到dom宽高改变为：{{randomTxt3}}
                </div>
            </div>
        </div>
        <code>
            <pre>
                let targetNode = document.getElementById('MutationObserver');

                let config = { attributes: true};

                let callback = function(mutations) {
                    for(let mutation of mutations) {
                        if (mutation.type == 'attributes') {
                            vm.randomTxt3 = `width:${mutation.target.style.width}, height:${mutation.target.style.height}`;
                        }
                    }
                };

                let observer = new MutationObserver(callback);
                observer.observe(targetNode as HTMLElement, config);
            </pre>
        </code>
    </section>
    <p class="page-end">The End</p>
  </div>
</template>

<script lang="ts">
    import Vue from 'vue';
    import Component from 'vue-class-component';

    @Component({
        // 所有的组件选项都可以放在这里
    })
    export default class domResize extends Vue {
        // data 在这
        message: string = 'DOM Resize'

        randomTxt: number|string = 0;
        dom1: any
        changeDom1 (): void {
            let random = 200 * Math.random();

            
            (document.getElementById('set-time-out-left') as HTMLElement).style.height = random + 'px';
            (document.getElementById('set-time-out-left') as HTMLElement).style.width = random + 'px';
        }
        cancelDom1 () {
            this.dom1.end();
        }

        randomTxt2: number|string = 0;
        change2dom (): void {
            let random = 200 * Math.random();

            
            (document.getElementById('iframe-left') as HTMLElement).style.height = random + 'px';
            (document.getElementById('iframe-left') as HTMLElement).style.width = random + 'px';
        }

        randomTxt3: number|string = 0;
        change3dom (): void {
            let random = 200 * Math.random();

            
            (document.getElementById('MutationObserver') as HTMLElement).style.height = random + 'px';
            (document.getElementById('MutationObserver') as HTMLElement).style.width = random + 'px';
        }
        created () {
            this.$nextTick(() => {
                let vm = this;
                class setInter {
                    interid: any;
                    dom: any;
                    fn: any;
                    oldParams: any = {
                        width: '',
                        height: ''
                    };
                    constructor(dom: HTMLElement, fn: Function) {
                        this.dom = dom;
                        this.fn = fn;
                    }
                    start() {
                        this.interid = setInterval(() => {
                            let width = this.dom.style.width;
                            let height = this.dom.style.height
                            if (width != this.oldParams.width || height != this.oldParams.height) {
                                this.fn({
                                    width,
                                    height
                                })
                                this.oldParams.width = width;
                                this.oldParams.height = height;
                            }
                        }, 500);
                    }
                    end() {
                        clearInterval(this.interid);
                    }
                }

                vm.dom1 = new setInter(document.getElementById('set-time-out-left') as HTMLElement, function (res) {
                    vm.randomTxt = `width:${res.width}, height:${res.height}`;
                });
                vm.dom1.start();


                function resize2 (dom:HTMLElement, cb: Function) {
                    this.el = dom;
                    this.cb = cb;
                    this.init();
                }
                resize2.prototype.init = function () {
                    let iframe = document.createElement('iframe') as HTMLIFrameElement;
                    this.el.style.position = 'relative';

                    let style = {
                        opacity: 0,
                        'z-index': '-9999',
                        position: 'absolute',
                        left: 0,
                        top: 0,
                        width: '100%',
                        height: '100%',
                    };
                    let styleText = '';
                    for (const key in style) {
                        styleText += (key + ':' + style[key] + ';');
                    }
                    iframe.style.cssText = styleText;

                    this.el.appendChild(iframe);
                    let self = this;
                    (iframe.contentWindow as Window).addEventListener('resize', function() {
                        self.cb({
                            width: self.el.style.width,
                            height: self.el.style.height
                        });
                    }, false);
                }

                new resize2(document.getElementById('iframe-left') as HTMLElement, function (res) {
                    vm.randomTxt2 = `width:${res.width}, height:${res.height}`;
                });


                let targetNode = document.getElementById('MutationObserver');

                let config = { attributes: true, childList: true};

                let callback = function(mutations) {
                    // (document.getElementById('MutationObserver') as HTMLElement).style.cssText = `height:${random}px;width:${random}px`;
                    // 这样就只会触发一次
                    for(let mutation of mutations) {
                        //   有两个type == 'attributes' 因为先后改变了width 和 height 两个属性
                        if (mutation.type == 'attributes') {
                            vm.randomTxt3 = `width:${mutation.target.style.width}, height:${mutation.target.style.height}`;
                        }
                    }
                };

                let observer = new MutationObserver(callback);
                observer.observe(targetNode as HTMLElement, config);
            });
        }
    }
</script>
<style lang="scss">
.proxy-test-event{
    .flex{
        margin-bottom: 20px;
    }
    .left{
        background: lightgrey;
        box-sizing: border-box;
        padding: 20px;
    }
    .left-contain{
        height: 100px;
        width: 100px;
        background: #54d8c9;
    }
    .right{
        box-sizing: border-box;
        padding: 20px;
        .context{
            padding: 20px;
        }
    }
}
</style>